﻿/*
 * 核心 - 远程获取、全局执行、错误捕获、多线程、URL路径解析
 * @author hutia
 * @email [email]hutia2@163.com[/email]
 *
 * 外部import  include导入编译，extends多重继承
 * 二次编译..
 */

/* Mini 远程获取 */
var _ = new function(){
	var cache = {};
	this.get = function(url, callback, obj){
		if(cache[url])return callback.apply(obj, [cache[url]]);
		var _ = (function(){
			try{ return new XMLHttpRequest(); }catch(e){}
			try{ return new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){}
			try{ return new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){}
		})();
		_.open("GET", url, true);
		_.onreadystatechange = function(){ if(_.readyState!=4)return; cache[url] = _.responseText; callback.apply(obj, [_.responseText, _]);}
		_.send();
	}   
}

/* 全局执行 */
function eval_global(s){ try{ if(window.execScript)window.execScript(s); else window.eval(s); }catch(e){ traceError(e); } }

/* 错误捕获 */
var debug = true;
if(typeof debug == "undefined")window.onerror = function(e){ traceError(e); return true; }
function traceError(e){
	var info = [];
	if(debug){
		if(typeof e == "object")for(var i in e)info.push(i+"\t: " + e[i]);
		else info.push(e);
		alert(info.join("\r\n"));
	}
}

/* 多线程 - 挂起 */
function suspend(url, callback, obj){ _.get(url, callback || arguments.callee.caller, obj); }


/* URL路径解析 */
function URL(s){
	var re = [], b = /^[\\\/]/.test(s)?"\/":"", e = /.+[\\\/]$/.test(s)?"\/":"", s = s.split(/[\\\/]/);
	for(var i=0; i<s.length; i++){
		if(s[i] == "..")re.pop();
		else if((s[i] != "" || i == s.length-1 || i == 0) && s[i] != ".")re.push(s[i]);
	}
	return b + re.join("\/") + e;
}


//全局执行指定地址的脚本，执行完毕后调用 onfinish 函数（可选）
function include(url, onfinish){
		if(typeof url == "string"){
		load_js(url, function(s){
			eval_global(s);
			if(onfinish)onfinish();
		});
	}else if(typeof url == "function"){
		try{ url(); }catch(e){ traceError(e); }
		if(onfinish)onfinish();
	}
}

//依次载入每个地址的脚本，编译并执行
function include_in_sequence(){
	var method = arguments.callee, started = false;
	if(!method.tasks)method.tasks = [];
	if(method.tasks.length > 0)started = true;
	for(var i=arguments.length-1; i>-1; i--)method.tasks.unshift(arguments[i]);
	function run(){ if(method.tasks.length > 0)include(method.tasks.shift(), run); }
	if(!started)run();
}

//载入指定url地址的脚本，编译后作为参数传递给 onfinish 函数
function load_js(url, onfinish){
	_.get(url, function(s){
		new Compiler(s, url, function(s){
			onfinish(Compiler.seal(s));
		});
	});
}

/*===============================
 * 核心 - 编译器
 * @author hutia
 * @email [email]hutia2@163.com[/email]
 *
 ===============================*/
//编译器类
function Compiler(source, baseURL, onfinish, extendsHash, obj){
	//关键字匹配
	var matcher = /\b(import)\s+([\w \t,.$]+)[;\r\n]|\b(extends)\s+([\w\s,.$]+)([^{]*)\{|\b(include)\s+([\w \t,.$]+)[;\r\n]/;
	//缓存，输出，头文件，解析指针，基础URL，任务列表，继承链
	var cache = source, result = [], imports = [], parse_point = 0, baseURL = URL(String(baseURL || "")), tasks = [], extendsHash;
	//当前方法
	var method = arguments.callee;
	//全局头文件hash
	if(!method.imported)method.imported = {};
	//初始化继承链
	if(!extendsHash)extendsHash = {};
	//记录当前文件
	extendsHash[baseURL] = true;
	//计算基础URL
	baseURL = baseURL.replace(/[\/\\][^\/\\]*$/, "");
	if(baseURL)baseURL = baseURL + "\/";
	//解析器
	function parse(prefixData){
		var j, s, asyn;
		//处理前缀数据
		if(prefixData)foundPrefixData(prefixData);
		//处理任务
		if(tasks.length > 0){
			asyn = tasks.shift();
			return suspend(asyn.url, asyn.callback, asyn);
		}
		//循环判断解析
		while(matcher.test(cache)){
			j = cache.search(matcher);
			if(j != 0)foundCData(cache.substring(0, j)); //解析普通数据
			s = cache.match(matcher);
			asyn = foundCMD(s); //解析命令数据
			cache = cache.substring(j + s[0].length, cache.length); //处理缓存
			if(asyn)return suspend(asyn.url, asyn.callback, asyn);//挂起
		}
		if(cache != "")foundCData(cache); //解析末尾的普通数据
		end(); //终止
	}
	function foundCMD(s){ //解析命令数据
		var t, url;
		if(s[1] == "import"){ //对于头文件
			t = String(s[2]).replace(/[^\w,.$]+/g, "").split(","); //解析头文件列表
			for(var i=t.length-1; i>-1; i--){
				url = URL(baseURL + t[i] + ".js"); //计算URL
				if(t[i] && !method.imported[url]){ //对于每个没有导入过的头文件（逆序）
					method.imported[url] = true; //记录URL为已导入
					//设置任务，自链表头部加入
					tasks.unshift({"url": url, callback:function(s){
						//编译获取的头文件
						new Compiler(s, this.url, function(s){
							//封装编译后的数据，记入头文件数据表（堆栈尾部入栈）
							imports.push(Compiler.seal(s));
							parse(); //继续恢复解析
						});
					}});
				}
			}
			return tasks.shift(); //自链表头部取出任务
		}else if(s[3] == "extends"){ //处理继承
			result.push((/\([\s\S]*?\)/.test(s[5])?s[5]:"()") + "{"); //输出当前Class声明
			t = String(s[4]).replace(/[^\w,.$]+/g, "").split(","); //解析继承列表
			//对于每个父类（逆序），设置任务，自链表头部加入
			for(var i=t.length-1; i>-1; i--){
				url = URL(baseURL + t[i] + ".js"); //计算URL
				if(t[i] && !extendsHash[url]){ //对于每个不在继承链上的文件
					extendsHash[url] = true; //记录到继承链
					tasks.unshift({"url": url, "name":t[i], callback:function(s){
						//编译获取的父类
						new Compiler(s, this.url, function(s){
							result.push("\r\nfunction " + this.name + "(){}\r\n"); //输出默认构造函数
							result.push(String(s.cdata).replace(/^[\s\S]*?\{/, "").replace(/\}[^\}]*?$/, "")); //输出父类函数体部分
							result.push("\r\ntry{ "+this.name+".apply(this, arguments); }catch(e){ traceError(e); }\r\n"); //尝试执行构造函数
							//记录父类的头文件信息，记入头文件数据表（堆栈尾部入栈）
							imports = imports.concat(s.imports);
							parse(); //继续恢复解析
						}, extendsHash, this);
					}});
				}
			}
			return tasks.shift(); //自链表头部取出任务
		}else if(s[6] == "include"){ //处理包含
			t = String(s[7]).replace(/[^\w,.$]+/g, "").split(","); //解析包含列表
			//对于每个包含文件（逆序），设置任务，自链表头部加入
			for(var i=t.length-1; i>-1; i--){
				url = URL(baseURL + t[i]); //计算URL
				if(t[i])tasks.unshift({"url": url, callback:function(s){
					//编译获取的包含文件
					new Compiler(s, this.url, function(s){
						result.push(String(s.cdata)); //输出文件体
						imports = imports.concat(s.imports); //记录头信息
						parse(); //继续恢复解析
					});
				}});
			}
			return tasks.shift(); //自链表头部取出任务
		}
	}
	function foundCData(s){ result.push(s); } //解析普通数据：直接输出
	function foundPrefixData(s){ cache = s + "\r\n" + cache; } //解析前缀数据：加载到缓存头部
	function end(){ //终止
		var re = {}; //用于返回的编译结果对象
		//编译后的数据体，处理其中的public声明
		re.cdata = result.join("").replace(/\bpublic(\s+function)?\s+([\w$]+)/g, function(s0, s1, s2){
			return "this." + s2 + " = " + s2 + "; function " + s2;
		});
		//编译后的头信息
		re.imports = [].concat(imports);
		onfinish.apply(obj, [re]); //回调解析终了函数
	}
	
	parse(); //开始解析
}

//编译器类静态方法：封装
//用于封装头部文件和函数体
Compiler.seal = function(s){
	//数据体，解析中间容器，类头部正则，输出
	var c = s.cdata, mc, i, reg = /^[^{]*function\s+([\w$]+)\s*(\([^\)]*\))\s*\{/, result = [].concat(s.imports);
	if(reg.test(c)){ //发现类头部声明
		mc = c.match(reg); //获取解析结果
		i = c.lastIndexOf("}"); //获取类结尾位置
		result.push(mc[0]); //输出类声明
		result.push("function " + mc[1] + mc[2] + "{}"); //输出默认构造函数
		result.push(c.substring(mc[0].length, i)); //输出类函数体
		result.push("try{" + mc[1] + ".apply(this, arguments);}catch(e){ traceError(e); }"); //试图执行构造函数
		result.push("try{ _initialize(); }catch(e){ if(typeof _initialize != \"undefined\")traceError(e); }"); //试图执行初始化函数
		result.push(c.substring(i)); //输出类结尾内容
	}else{ //解析失败，直接输出内容
		result.push(c);
	}
	return result.join("\r\n");
}